library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity link_controller is

  port ( clk              : in  std_logic;
         host_address     : in  std_logic_vector(23 DownTo 0);
         pixel_value      : in  std_logic;
         data_in_n        : in  std_logic;
         data_in_ne       : in  std_logic;
         data_in_nw       : in  std_logic;
         data_in_s        : in  std_logic;
         data_in_se       : in  std_logic;
         data_in_sw       : in  std_logic;
         data_in_e        : in  std_logic;
         data_in_w        : in  std_logic;
         data_out_n       : out std_logic;
         data_out_ne      : out std_logic;
         data_out_nw      : out std_logic;
         data_out_s       : out std_logic;
         data_out_se      : out std_logic;
         data_out_sw      : out std_logic;
         data_out_e       : out std_logic;
         data_out_w       : out std_logic;
         links_complete   : out std_logic;
         controller_label : out std_logic_vector(23 DownTo 0)
       );

end link_controller; 

architecture bhv of link_controller is
  
  component link is

    port ( clk             : in  std_logic;
           enable          : in  std_logic;
           initialize      : in  std_logic;
           reset_in        : in  std_logic;
           link_data_in    : in  std_logic;
           h_target_label  : in  std_logic_vector(23 DownTo 0);
           h_name          : in  std_logic_vector(23 DownTo 0);
           dir             : in  integer;
           reset_out       : out std_logic;
           link_data_out   : out std_logic;
           link_killed     : out std_logic;
           b_position      : out integer;
           b_label_current : out std_logic_vector(23 DownTo 0);
           link_complete   : out std_logic
         );
    
  end component;

  -- type defs
  type controller_state_t is (  init_links,
                                set_target_labels,
                                clear_link_resets,
                                enable_links,
                                clock_link_1,
                                clock_link_2,
                                clock_link_3,
                                clock_link_4,
                                clock_link_5,
                                clock_link_6,
                                clock_link_7,
                                clock_link_8,
                                disable_links,
                                let_links_settle,
                                get_min_shift,
                                get_max_label,
                                compare_n_reset,
                                update_all_links,
                                check_for_completion
                             );

  type link_location_t is (  none, 
                             n, 
                             ne, 
                             nw, 
                             s, 
                             se, 
                             sw, 
                             e, 
                             w
                          );

  type listener_lookup_t is array (7 DownTo 0) of link_location_t;

  -- Global Signals

  -- controller specific signals
  signal controller_host_address     : std_logic_vector(23 DownTo 0);
  signal controller_pixel            : std_logic;

  -- link a specific signals
  signal init_n                      : std_logic;
  signal dir_n                       : integer;
  signal enable_n                    : std_logic;
  signal reset_n                     : std_logic;
  signal reset_out_n                 : std_logic;
  signal target_label_n              : std_logic_vector(23 DownTo 0);
  signal link_killed_n               : std_logic;
  signal b_position_n                : integer;
  signal b_label_current_n           : std_logic_vector(23 DownTo 0);
  signal link_complete_n             : std_logic;

  signal init_ne                     : std_logic;
  signal dir_ne                      : integer;
  signal enable_ne                   : std_logic;
  signal reset_ne                    : std_logic;
  signal reset_out_ne                : std_logic;
  signal target_label_ne             : std_logic_vector(23 DownTo 0);
  signal link_killed_ne              : std_logic;
  signal b_position_ne               : integer;
  signal b_label_current_ne          : std_logic_vector(23 DownTo 0);
  signal link_complete_ne            : std_logic;

  signal init_nw                     : std_logic;
  signal dir_nw                      : integer;
  signal enable_nw                   : std_logic;
  signal reset_nw                    : std_logic;
  signal reset_out_nw                : std_logic;
  signal target_label_nw             : std_logic_vector(23 DownTo 0);
  signal link_killed_nw              : std_logic;
  signal b_position_nw               : integer;
  signal b_label_current_nw          : std_logic_vector(23 DownTo 0);
  signal link_complete_nw            : std_logic;

  signal init_s                      : std_logic;
  signal dir_s                       : integer;
  signal enable_s                    : std_logic;
  signal reset_s                     : std_logic;
  signal reset_out_s                 : std_logic;
  signal target_label_s              : std_logic_vector(23 DownTo 0);
  signal link_killed_s               : std_logic;
  signal b_position_s                : integer;
  signal b_label_current_s           : std_logic_vector(23 DownTo 0);
  signal link_complete_s             : std_logic;

  signal init_se                     : std_logic;
  signal dir_se                      : integer;
  signal enable_se                   : std_logic;
  signal reset_se                    : std_logic;
  signal reset_out_se                : std_logic;
  signal target_label_se             : std_logic_vector(23 DownTo 0);
  signal link_killed_se              : std_logic;
  signal b_position_se               : integer;
  signal b_label_current_se          : std_logic_vector(23 DownTo 0);
  signal link_complete_se            : std_logic;

  signal init_sw                     : std_logic;
  signal dir_sw                      : integer;
  signal enable_sw                   : std_logic;
  signal reset_sw                    : std_logic;
  signal reset_out_sw                : std_logic;
  signal target_label_sw             : std_logic_vector(23 DownTo 0);
  signal link_killed_sw              : std_logic;
  signal b_position_sw               : integer;
  signal b_label_current_sw          : std_logic_vector(23 DownTo 0);
  signal link_complete_sw            : std_logic;

  signal init_e                      : std_logic;
  signal dir_e                       : integer;
  signal enable_e                    : std_logic;
  signal reset_e                     : std_logic;
  signal reset_out_e                 : std_logic;
  signal target_label_e              : std_logic_vector(23 DownTo 0);
  signal link_killed_e               : std_logic;
  signal b_position_e                : integer;
  signal b_label_current_e           : std_logic_vector(23 DownTo 0);
  signal link_complete_e             : std_logic;

  signal init_w                      : std_logic;
  signal dir_w                       : integer;
  signal enable_w                    : std_logic;
  signal reset_w                     : std_logic;
  signal reset_out_w                 : std_logic;
  signal target_label_w              : std_logic_vector(23 DownTo 0);
  signal link_killed_w               : std_logic;
  signal b_position_w                : integer;
  signal b_label_current_w           : std_logic_vector(23 DownTo 0);
  signal link_complete_w             : std_logic;

begin

  link_n  : link port map ( clk, 
                            enable_n,
                            init_n, 
                            reset_n,
                            data_in_n,
                            target_label_n,
                            controller_host_address,
                            dir_n,
                            reset_out_n,
                            data_out_n,
                            link_killed_n,
                            b_position_n,
                            b_label_current_n,
                            link_complete_n
                          );

  link_ne : link port map ( clk, 
                            enable_ne,
                            init_ne, 
                            reset_ne,
                            data_in_ne,
                            target_label_ne,
                            controller_host_address,
                            dir_ne,
                            reset_out_ne,
                            data_out_ne,
                            link_killed_ne,
                            b_position_ne,
                            b_label_current_ne,
                            link_complete_ne
                          );

  link_nw : link port map ( clk, 
                            enable_nw,
                            init_nw, 
                            reset_nw,
                            data_in_nw,
                            target_label_nw,
                            controller_host_address,
                            dir_nw,
                            reset_out_nw,
                            data_out_nw,
                            link_killed_nw,
                            b_position_nw,
                            b_label_current_nw,
                            link_complete_nw
                          );

  link_s  : link port map ( clk, 
                            enable_s,
                            init_s, 
                            reset_s,
                            data_in_s,
                            target_label_s,
                            controller_host_address,
                            dir_s,
                            reset_out_s,
                            data_out_s,
                            link_killed_s,
                            b_position_s,
                            b_label_current_s,
                            link_complete_s
                          );

  link_se : link port map ( clk, 
                            enable_se,
                            init_se, 
                            reset_se,
                            data_in_se,
                            target_label_se,
                            controller_host_address,
                            dir_se,
                            reset_out_se,
                            data_out_se,
                            link_killed_se,
                            b_position_se,
                            b_label_current_se,
                            link_complete_se
                          );

  link_sw : link port map ( clk, 
                            enable_sw,
                            init_sw, 
                            reset_sw,
                            data_in_sw,
                            target_label_sw,
                            controller_host_address,
                            dir_sw,
                            reset_out_sw,
                            data_out_sw,
                            link_killed_sw,
                            b_position_sw,
                            b_label_current_sw,
                            link_complete_sw
                          );

  link_e  : link port map ( clk, 
                            enable_e,
                            init_e, 
                            reset_e,
                            data_in_e,
                            target_label_e,
                            controller_host_address,
                            dir_e,
                            reset_out_e,
                            data_out_e,
                            link_killed_e,
                            b_position_e,
                            b_label_current_e,
                            link_complete_e
                          );

  link_w  : link port map ( clk, 
                            enable_w,
                            init_w, 
                            reset_w,
                            data_in_w,
                            target_label_w,
                            controller_host_address,
                            dir_w,
                            reset_out_w,
                            data_out_w,
                            link_killed_w,
                            b_position_w,
                            b_label_current_w,
                            link_complete_w
                          );

  link_controller_control: process ( clk )

    variable controller_state : controller_state_t := init_links;
    variable link_min_shift : integer;
    variable link_max_label : std_logic_vector(23 DownTo 0);
    variable current_max_link : link_location_t := none;
    variable listener_lookup : listener_lookup_t;

    procedure print_any_label ( print_label : std_logic_vector ) is
    begin

      --report (" " & integer'image( to_integer(unsigned( controller_host_address ) ) ) & " Printing: "
      report ( "printing: "
                                       & std_logic'image(print_label(23))
                                       & std_logic'image(print_label(23))
                                       & std_logic'image(print_label(22))
                                       & std_logic'image(print_label(21))
                                       & std_logic'image(print_label(20))
                                       & std_logic'image(print_label(19))
                                       & std_logic'image(print_label(18))
                                       & std_logic'image(print_label(17))
                                       & std_logic'image(print_label(16))
                                       & std_logic'image(print_label(15))
                                       & std_logic'image(print_label(14))
                                       & std_logic'image(print_label(13))
                                       & std_logic'image(print_label(12))
                                       & std_logic'image(print_label(11))
                                       & std_logic'image(print_label(10))
                                       & std_logic'image(print_label(9))
                                       & std_logic'image(print_label(8))
                                       & std_logic'image(print_label(7))
                                       & std_logic'image(print_label(6))
                                       & std_logic'image(print_label(5))
                                       & std_logic'image(print_label(4))
                                       & std_logic'image(print_label(3))
                                       & std_logic'image(print_label(2))
                                       & std_logic'image(print_label(1))
                                       & std_logic'image(print_label(0)));

    end procedure print_any_label;

    impure function get_link_target_label ( listener : link_location_t ) return std_logic_vector is
      variable result : std_logic_vector(23 DownTo 0) := "000000000000000000000000";
    begin

      case listener is
        when none =>
        when n =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " north" );
          result := b_label_current_n;
        when ne =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " north east" );
          result := b_label_current_ne;
        when nw =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " north west" );
          result := b_label_current_nw;
        when s =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " south" );
          result := b_label_current_s;
        when se =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " south east" );
          result := b_label_current_se;
        when sw =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " south west" );
          result := b_label_current_sw;
        when e =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " east" );
          result := b_label_current_e;
        when w =>
          --report (integer'image(to_integer(unsigned(controller_host_address))) & " west" );
          result := b_label_current_w;
      end case;

      --print_any_label( result );

      return result;

    end function get_link_target_label;

    procedure activate_links is
    begin

      enable_n  <= '1';
      enable_ne <= '1';
      enable_nw <= '1';
      enable_s  <= '1';
      enable_se <= '1';
      enable_sw <= '1';
      enable_e  <= '1';
      enable_w  <= '1';

    end procedure activate_links;

    procedure deactivate_links is
    begin

      enable_n  <= '0';
      enable_ne <= '0';
      enable_nw <= '0';
      enable_s  <= '0';
      enable_se <= '0';
      enable_sw <= '0';
      enable_e  <= '0';
      enable_w  <= '0';

    end procedure deactivate_links;

    procedure find_min_shift is
      variable min_shift : integer := 99;
    begin


      --report ("Link Killed North:" & std_logic'image(link_killed_n));
      if ( link_killed_n = '0' ) then
        if ( min_shift > b_position_n ) then
          min_shift := b_position_n;
        end if;
      end if;

      if ( link_killed_ne = '0' ) then
        if ( min_shift > b_position_ne ) then
          min_shift := b_position_ne;
        end if;
      end if;

      if ( link_killed_nw = '0' ) then
        if ( min_shift > b_position_nw ) then
          min_shift := b_position_nw;
        end if;
      end if;

      if ( link_killed_s = '0' ) then
        if ( min_shift > b_position_s ) then
          min_shift := b_position_s;
        end if;
      end if;

      if ( link_killed_se = '0' ) then
        if ( min_shift > b_position_se ) then
          min_shift := b_position_se;
        end if;
      end if;

      if ( link_killed_sw = '0' ) then
        if ( min_shift > b_position_sw ) then
          min_shift := b_position_sw;
        end if;
      end if;

      if ( link_killed_e = '0' ) then
        if ( min_shift > b_position_e ) then
          min_shift := b_position_e;
        end if;
      end if;

      if ( link_killed_w = '0' ) then
        if ( min_shift > b_position_w ) then
          min_shift := b_position_w;
        end if;
      end if;

      link_min_shift := min_shift;

      if ( link_min_shift /= 99 ) then
        --report (integer'image(to_integer(unsigned(controller_host_address)))
        --        & " Printing link_min_shift: " & integer'image(link_min_shift));
      end if;

    end procedure find_min_shift;

    procedure find_max_label is
      variable max_label : std_logic_vector(23 DownTo 0) := "000000000000000000000000";
    begin

      if ( link_killed_n = '0' ) then
        if ( ( unsigned( b_label_current_n ) srl ( 23 - link_min_shift ) ) > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_n) srl ( 23 - link_min_shift ) );
          current_max_link := n;
        end if;
      end if;

      if ( link_killed_ne = '0' ) then
        if ( ( unsigned( b_label_current_ne ) srl ( 23 - link_min_shift ) )  > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_ne) srl ( 23 - link_min_shift ) );
          current_max_link := ne;
        end if;
      end if;

      if ( link_killed_nw = '0' ) then
        if ( ( unsigned( b_label_current_nw ) srl ( 23 - link_min_shift ) )  > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_nw) srl ( 23 - link_min_shift ) );
          current_max_link := nw;
        end if; 
      end if;

      if ( link_killed_s = '0' ) then
        if ( ( unsigned( b_label_current_s ) srl ( 23 - link_min_shift ) )  > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_s) srl ( 23 - link_min_shift ) );
          current_max_link := s;
        end if;
      end if;

      if ( link_killed_se = '0' ) then
        if ( ( unsigned( b_label_current_se ) srl ( 23 - link_min_shift ) )  > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_se) srl ( 23 - link_min_shift ) );
          current_max_link := se;
        end if;
      end if;

      if ( link_killed_sw = '0' ) then
        if ( ( unsigned( b_label_current_sw ) srl ( 23 - link_min_shift ) )  > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_sw) srl ( 23 - link_min_shift ) );
          current_max_link := sw;
        end if;
      end if;

      if ( link_killed_e = '0' ) then
        if ( ( unsigned( b_label_current_e ) srl ( 23 - link_min_shift ) )  > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_e) srl ( 23 - link_min_shift ) );
          current_max_link := e;
        end if;
      end if;

      if ( link_killed_w = '0' ) then
        if ( ( unsigned( b_label_current_w ) srl ( 23 - link_min_shift ) )  > unsigned( max_label ) ) then
          max_label := std_logic_vector( unsigned(b_label_current_w) srl ( 23 - link_min_shift ) );
          current_max_link := w;
        end if;
      end if;

      link_max_label := max_label;

      --report("Print Max Label");
      --print_any_label( link_max_label );

    end procedure find_max_label;

    procedure compare_and_reset_links is
    begin

      if ( link_killed_n = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_n ) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " north reset");
          reset_n <= '1';
          listener_lookup(0) := current_max_link;
        end if;
      end if;

      if ( link_killed_ne = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_ne ) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " north east reset");
          reset_ne <= '1';
          listener_lookup(1) := current_max_link;
        end if;
      end if;

      if ( link_killed_nw = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_nw ) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " north west reset");
          reset_nw <= '1';
          listener_lookup(2) := current_max_link;
        end if;
      end if;

      if ( link_killed_s = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_s ) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " south reset");
          reset_s <= '1';
          listener_lookup(3) := current_max_link;
        end if;
      end if;

      if ( link_killed_se = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_se) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " south east reset");
          reset_se <= '1';
          listener_lookup(4) := current_max_link;
        end if;
      end if;

      if ( link_killed_sw = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_sw ) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " south west reset");
          reset_sw <= '1';
          listener_lookup(5) := current_max_link;
        end if;
      end if;

      if ( link_killed_e = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_e ) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " east reset");
          reset_e <= '1';
          listener_lookup(6) := current_max_link;
        end if;
      end if;

      if ( link_killed_w = '0' ) then
        if ( unsigned(link_max_label) > ( unsigned( b_label_current_w ) srl ( 23 - link_min_shift ) ) ) then
          --report(integer'image(to_integer(unsigned(controller_host_address))) & " west reset");
          reset_w <= '1';
          listener_lookup(7) := current_max_link;
        end if;
      end if;

    end procedure compare_and_reset_links;

    procedure update_link_listeners is
    begin

      if ( link_killed_n = '0' ) then
        if ( none = listener_lookup(0) ) then
        else
          --report "north target label change: ";
          target_label_n <= get_link_target_label(listener_lookup(0));
        end if;
      end if;

      if ( link_killed_ne = '0' ) then
        if ( none = listener_lookup(1) ) then
        else
          --report "north east target label change: ";
          target_label_ne <= get_link_target_label(listener_lookup(1)); 
        end if;
      end if;

      if ( link_killed_nw = '0' ) then
        if ( none = listener_lookup(2) ) then
        else
          --report "north west target label change: ";
          target_label_nw <= get_link_target_label(listener_lookup(2));
        end if;
      end if;

      if ( link_killed_s = '0' ) then
        if ( none = listener_lookup(3) ) then
        else
          --report "south target label change: ";
          target_label_s  <= get_link_target_label(listener_lookup(3));
        end if;
      end if;

      if ( link_killed_se = '0' ) then
        if ( none = listener_lookup(4) ) then
        else
          --report "south east target label change: ";
          target_label_se <= get_link_target_label(listener_lookup(4));
        end if;
      end if;

      if ( link_killed_sw = '0' ) then
        if ( none = listener_lookup(5) ) then
        else
          --report "south west target label change: ";
          target_label_sw <= get_link_target_label(listener_lookup(5));
        end if;
      end if;

      if ( link_killed_e = '0' ) then
        if ( none = listener_lookup(6) ) then
        else
          --report "east target label change: ";
          target_label_e  <= get_link_target_label(listener_lookup(6));
        end if;
      end if;

      if ( link_killed_w = '0' ) then
        if ( none = listener_lookup(7) ) then
        else
          --report "west target label change: ";
          target_label_w  <= get_link_target_label(listener_lookup(7));
        end if;
      end if;

    end procedure update_link_listeners;

    procedure init_all_links is
    begin

      init_n  <= '1';
      dir_n   <= 0;

      init_ne <= '1';
      dir_ne  <= 1;

      init_nw <= '1';
      dir_nw  <= 2;

      init_s  <= '1';
      dir_s   <= 3;

      init_se <= '1';
      dir_se  <= 4;

      init_sw <= '1';
      dir_sw  <= 5;

      init_e  <= '1';
      dir_e   <= 6;

      init_w  <= '1';
      dir_w   <= 7;

    end procedure init_all_links;

    procedure are_all_links_complete is
      variable result : std_logic := '1';
    begin

      result := result and link_complete_n;
      result := result and link_complete_ne;
      result := result and link_complete_nw;
      result := result and link_complete_s;
      result := result and link_complete_se;
      result := result and link_complete_sw;
      result := result and link_complete_e;
      result := result and link_complete_w;

      -- WARNING: this could cause a problem on a killed link
      if ( result = '1' ) then

        controller_label <= link_max_label;

      else

        controller_label <= controller_host_address;

      end if;

      links_complete <= result;

    end procedure are_all_links_complete;

    procedure set_links_to_host_address is
    begin

      target_label_n  <= controller_host_address;
      target_label_ne <= controller_host_address;
      target_label_nw <= controller_host_address;
      target_label_s  <= controller_host_address;
      target_label_se <= controller_host_address;
      target_label_sw <= controller_host_address;
      target_label_e  <= controller_host_address;
      target_label_w  <= controller_host_address;

    end procedure set_links_to_host_address;

    procedure clear_all_link_resets is 
    begin

      reset_n  <= '0';
      reset_ne <= '0';
      reset_nw <= '0';
      reset_s  <= '0';
      reset_se <= '0';
      reset_sw <= '0';
      reset_e  <= '0';
      reset_w  <= '0';

    end procedure clear_all_link_resets;

  begin

    if( clk'event and clk = '1' ) then
      case controller_state is 

        when init_links =>

          deactivate_links;
          init_all_links;

          controller_state := set_target_labels;
        when set_target_labels =>

          set_links_to_host_address;

          controller_state := clear_link_resets;
        when clear_link_resets =>

          clear_all_link_resets;
          are_all_links_complete;

          controller_state := enable_links;
        when enable_links =>


          activate_links;

          controller_state := clock_link_1;
        when clock_link_1 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := clock_link_2;
        when clock_link_2 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := clock_link_3;
        when clock_link_3 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := clock_link_4;
        when clock_link_4 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := clock_link_5;
        when clock_link_5 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := clock_link_6;
        when clock_link_6 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := clock_link_7;
        when clock_link_7 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := clock_link_8;
        when clock_link_8 =>

          -- nothing is done on this level, clock is pumped through

          controller_state := disable_links;
        when disable_links =>

          deactivate_links;
          clear_all_link_resets;

          controller_state := let_links_settle;
        when let_links_settle =>
          
          -- do nothing

          controller_state := get_min_shift;
        when get_min_shift =>

          find_min_shift;

          controller_state := get_max_label;
        when get_max_label =>

          find_max_label;

          controller_state := compare_n_reset;
        when compare_n_reset =>
          compare_and_reset_links;
          
          controller_state := update_all_links;
        when update_all_links =>

          update_link_listeners;

          controller_state := check_for_completion;
        when check_for_completion =>

          are_all_links_complete;

          controller_state := enable_links;
      end case;
        
    end if;

  end process link_controller_control;


  set_host_address_for_controller : process  ( host_address )
  begin

    if ( host_address'event ) then

      if ( controller_pixel = '0' ) then
        --report ("Overriding address because pixel is 0");

        controller_host_address <= "100000000000000000000000";
        
      else

        controller_host_address <= host_address;

      end if;

    end if;

  end process set_host_address_for_controller;

  set_pixel_for_controller : process ( pixel_value )
  begin

    if ( pixel_value'event ) then

      --report ("Settting Pixel To: " & std_logic'image(pixel_value));

      controller_pixel <= pixel_value;

    end if;

  end process set_pixel_for_controller;

end bhv;

